package service;

import model.ClickEvent;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.function.Consumer;

/**
 * @Author: xwg
 * @CreateDate: 2023/4/9
 */


public class BasicPC {

    /**
     * 多线程编程和面向对象编程和函数式编程一样，也是一种书写代码的思路，模拟工业中流水线生产工人 https://www.ixigua.com/6864097250801353228
     * 例如：手机生产中，让工人甲不断给手机装配贴膜，装配好后放进传送带，工人乙取下，装配纸箱包装盒与充电线等。
     * 多线程编程可以通过接入死循环让程序成为服务，永不停止工作，每一次循环称为一个tick。
     * 多线程编程可以通过接入阻塞器让程序按照情况进入假死休眠状态（半导体？），从而避免死循环烧机器。
     * 多线程编程可以通过多个线程栈内存共同访问同一个堆内存对象，达到信息交互的。而这个对象最好是具有缓冲性能的list容器
     * 经验表明，如果某个list容器能有先进先出的queue特点，再附带一个阻塞器，在多线程编程中用于多线程之间通信将会是首选方案。
     * 多线程编程的产物被称为引擎engine，如tomcat服务器，是应用程序比较内核的部分，编程困难但重用度高与业务无关，经常由高手编写，新手只编写回调函数配合使用。
     * 在多线程开发当中，
     * 如果生产者处理速度很快，
     * 而消费者处理速度很慢，
     * 那么生产者就必须等待消费者处理完，
     * 才能继续生产数据。同样的道理，
     * 如果消费者的处理能力大于生产者，那么消费者就必须等待生产者。
     * <p>
     * 为了解决这种生产消费能力不均衡的问题，所以便有了生产者和消费者模式。
     * <p>
     * 1
     * <p>
     * 假设你要寄一封平信，大致过程如下：
     * <p>
     * 1、你把信写好——相当于生产者制造数据 new event
     * <p>
     * 2、你把信放入邮筒——相当于生产者把数据放入缓冲区 put event into channel
     * <p>
     * 3、邮递员把信从邮筒取出——相当于消费者把数据取出缓冲区 take event from channel
     * <p>
     * 4、邮递员把信拿去邮局做相应的处理——相当于消费者处理数据 运行监听函数回调函数 onXXX
     */
//    step1 关闭消费线程 观察生产线程的阻塞效果
//    step2 关闭生产线程 观察消费线程的阻塞效果
//    step3 同时开启生产消费 调节生产与消费速率比 分别观察效果
//    step4 取消消费线程的默认阻塞 观察生产消费与方法调用的特点

//    总结 在用户通过点鼠标键盘操作的场景下， 通过鼠标和键盘生产事件被认为速率极慢
//    一般高性能cpu3GHz以上的情况下 缓冲队列大多是空置的，所以事件本身可以认为是对监听函数的调用。
//    这种通过缓冲队列调用函数的方式，不会因为被调用函数不存在而报错，因为它本质是在往缓冲区中提交。
//    所以 生产消费模型本质是一种代码调用，是一种可以跨线程的尝试型(不报错)代码调用。
//    注意 这个list具有很多名字:队列Queue 事件队列EventQueue 阻塞队列BlockingQueue 缓冲区Buffer 通道Channel 缓冲队列

//    拓展：案例中缓冲队列BlockingQueue如果升级成为socket端口，则生产消费线程可以分别写在不同的应用程序中，跨语言跨程序跨电脑，
//    缓冲对列的升级代码程序即称为消息中间件MessageQueue,如kafka，rabbitMQ等。clickEvent即升级为可序列化的消息协议，如ws stomp的等。
//    以上介绍的是简易版本的生产消费模型，或者称为广义的生产消费模型，特点是只考虑一个生产者一个消费者，

//    免责声明：真正的生产消费模型在于多个消费者与发布订阅模型有较大区别，而click事件监听准确来讲属于发布订阅模型，此处不展开论述。
    public static void main(String[] args) {
        BlockingQueue<ClickEvent> eventChannel = new ArrayBlockingQueue<>(6);
//        new Thread(() -> {
//            List<String> names = Arrays.asList("div", "button", "li", "span");
//
//            while (true) {
//                System.out.println("*********新一轮生产开始********");
//                double i = Math.floor(Math.random() * names.size());
//                ClickEvent clickEvent = new ClickEvent(names.get((int) i),
//                        (int) (Math.random() * 100));
//                System.out.println("**" + Thread.currentThread().getName()
//                        + " 生产了 " + clickEvent);
//
//                try {
//                    eventChannel.put(clickEvent);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                System.out.println("*********tick end********");
//                try {
//                    Thread.sleep(800);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//
//            }
//
//
//        }, "producer").start();
        new Thread(() -> {
            while (true) {
                System.out.println("-----新一轮消费开始---------");
                try {
                    ClickEvent e = eventChannel.take();
//                    js语言监听函数 let onclick =(event)=>{ ...console.log(event)... }
//                    onclick(e);
//                    java语言监听函数
//                    Consumer onclick = (event) -> {
//                        System.out.println("--" + Thread.currentThread().getName()
//                                + " 消费了 " + event);
//                    };
//                    onclick.accept(e);
                    {
                        System.out.println("--" + Thread.currentThread().getName()
                                + " 消费了 " + e);
                    };
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
                System.out.println("--------tick end--------");
//                try {
//                    Thread.sleep(1600);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
            }

        }, "consumer").start();

        new Thread(() -> {
            while (true) {

                System.err.println("观察员 ：" + Thread.currentThread().getName() +
                        " 个数:" + eventChannel.size() + "  "
                        + eventChannel);


                try {
                    Thread.sleep(600);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }, "watcher").start();
    }
}
